/* -*- mode: C++; c-basic-offset: 8 -*-
 *
 * jaboti.cpp - Jabber Robot in C++ with Gloox
 *
 */

#include <iostream>
#include <string>
#include <time.h>

#include <gloox/gloox.h>
#include <gloox/jid.h>
#include <gloox/client.h>
#include <gloox/connectionlistener.h>
#include <gloox/disco.h>
#include <gloox/presence.h>
#include <gloox/presencehandler.h>
#include <gloox/message.h>
#include <gloox/messagehandler.h>
#include <gloox/loghandler.h>
#include <gloox/logsink.h>

using namespace std;
using namespace gloox;

class Jaboti : public ConnectionListener, PresenceHandler, MessageHandler, LogHandler
{
public:
	Jaboti() {}
	virtual ~Jaboti() { delete client; }
	void start(char *, char *, char *, bool);
	void onConnect();
	void onDisconnect(gloox::ConnectionError);
	bool onTLSConnect(const gloox::CertInfo&);
	void handlePresence(const gloox::Presence&);
	void handleMessage(const gloox::Message&, gloox::MessageSession*);
	void handleLog(gloox::LogLevel, gloox::LogArea, const std::string&);
	void setStatusOnline();
	void setStatusAway();
	void setStatusOffline();
private:
	Client *client;
};

void Jaboti::start(char *jid, char *passwd, char *server=0, bool debug=false)
{
	ConnectionError status = ConnNoError;
	JID fulljid(string(jid) + string("/jaboti"));
	client = new Client(fulljid, passwd);
	if (server && *server != '\0') client->setServer(server);
	client->registerConnectionListener(this);
	client->registerPresenceHandler(this);
	client->registerMessageHandler(this);
	client->disco()->setVersion("Jaboti", "2009");
	client->disco()->setIdentity("client", "bot");
	if (debug)
		client->logInstance().registerLogHandler(LogLevelDebug,
							 LogAreaAll, this);

	this->setStatusOnline();

	if (client->connect(false)) {
		while (status == ConnNoError) {
			status = client->recv();
		}
	}
	cerr << "recv() status is " << status << endl;
}

void Jaboti::onConnect()
{
	cout << time(0) << " connected" << endl;
}

void Jaboti::onDisconnect(ConnectionError e)
{
	string err;
	switch (e) {
	case ConnStreamError:
		err = client->streamError();
		break;
	default:
		err = string("?");
	}
	cout << time(0) << " disconnected " << err << endl;
}

bool Jaboti::onTLSConnect(const CertInfo& info)
{
	return true;
}

void Jaboti::handlePresence(const gloox::Presence& presence)
{
	string prestype; 
	switch (presence.presence()) {
	case gloox::Presence::Available:
		prestype = string("online");
		break;
	case gloox::Presence::Chat:
		prestype = string("chat");
		break;
	case gloox::Presence::Away:
		prestype = string("away");
		break;
	case gloox::Presence::DND:
		prestype = string("dnd");
		break;
	case gloox::Presence::XA:
		prestype = string("xaway");
		break;
	case gloox::Presence::Unavailable:
		prestype = string("offline");
		break;
	default:
		prestype = string("?");
	}

	cout << time(0) << " presence from " << presence.from().full() \
	     << " " << prestype << " (" << presence.status() << ") " << endl;
}

void Jaboti::handleMessage(const gloox::Message& msg, gloox::MessageSession* session)
{
	cout << time(0) << " message " << msg.body() << endl;
}

void Jaboti::handleLog(gloox::LogLevel level, gloox::LogArea area, const std::string& message)
{
	cerr << time(0) << " " << level << " " << area << " " \
	     << message << endl;
}

void Jaboti::setStatusOnline()
{
	client->setPresence(Presence::Available, 0);
}

void Jaboti::setStatusAway()
{
	client->setPresence(Presence::Away, 0);
}

void Jaboti::setStatusOffline()
{
	client->setPresence(Presence::Unavailable, 0);
}

int main(int argc, char *argv[])
{
	bool debug = false;
	char *jid = 0;
	char *passwd = "";
	char *server = 0;
	char *progname = argv[0];
	Jaboti *jaboti = new Jaboti();

	if (*++argv && string(*argv).compare("-h") == 0) {
		cout << progname << " [-h|-d] [-j <jid>] [-p <password>] [-s <server>]" << endl;
		return 0;
	}
	if (*argv && string(*argv).compare("-d") == 0) {
		debug = true;
		argv++;
	}
	if (*argv && string(*argv).compare("-j") == 0) {
		if (*++argv) {
			jid = *argv;
			argv++;
		} else {
			cerr << "error: option -j requires a JID" << endl;
			return 1;
		}
	}
	if (*argv && string(*argv).compare("-p") == 0) {
		if (*++argv) {
			passwd = *argv;
			argv++;
		} else {
			cerr << "error: option -p requires a PASSWORD" << endl;
			return 1;
		}
	}
	if (*argv && string(*argv).compare("-s") == 0) {
		if (*++argv) {
			server = *argv;
			argv++;
		} else {
			cerr << "error: option -s requires a SERVER" << endl;
			return 1;
		}
	}

	if (!jid) {
		cerr << "error: please, provide a jid and password" << endl;
		return 1;
	}
	jaboti->start(jid, passwd, server, debug);

	return 0;
}
